﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using LFSRecord2.Events;
using LFSRecord2.Model;
using LFSRecord2.Model.UserActions;
using LFSRecord2.ViewModel;
using LFSRecord2.View.Dialogs;
using LFSRecord2.Structures;
using System.Diagnostics;
using LFSRecord2.Model.Replay;

namespace LFSRecord2.View
{
    /// <summary>
    /// Interaction logic for TimelineLayerView.xaml
    /// </summary>
    public partial class TimelineLayerInfoView : UserControl
    {
        public TimelineLayerInfoView()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            CompLayerBase layer = (CompLayerBase)DataContext;
            if (layer.LayerType == CompLayerTypes.ReplayControl)
                LayerBindingControl.Visibility = Visibility.Collapsed;

            SetupContextMenu();
        }

        private void UserControl_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
        }

        private void CollapseImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (PropertyItemsControl.Visibility == Visibility.Collapsed)
            {
                PropertyItemsControl.Visibility = Visibility.Visible;
            }
            else
            {
                PropertyItemsControl.Visibility = Visibility.Collapsed;
            }
        }

        private void LayerNameLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            CompLayerBase layer = (CompLayerBase)DataContext;

            if (!layer.IsSelected)
            {
                LfsRecordController.project.DeselectAll();
                layer.IsSelected = true;
            }
        }

        public void SetupContextMenu()
        {
            // Create context menu
            MenuItem mi, mi2;
            Binding myBinding;
            ContextMenu cm = new ContextMenu();
            CompLayerBase layer = (CompLayerBase)DataContext;

            // Add layer
            mi = new MenuItem();
            mi.Name = "AddLayer";
            mi.Header = "Add Layer";

            mi2 = new MenuItem();
            mi2.Name = "LookCamera";
            mi2.Header = "Look Camera";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.LookCamera;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "FreeCamera";
            mi2.Header = "Free Camera";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.FreeCamera;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "NullLayer";
            mi2.Header = "Null";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.Null;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "ReplayControl";
            mi2.Header = "Replay Control";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.ReplayControl;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "ReplayData";
            mi2.Header = "Replay Data";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.ReplayData;
            mi.Items.Add(mi2);

            mi2 = new MenuItem();
            mi2.Name = "AudioLayer";
            mi2.Header = "Audio Track";
            mi2.Command = AddLayerClickedCommand;
            mi2.CommandParameter = CompLayerTypes.Audio;
            mi.Items.Add(mi2);

            cm.Items.Add(mi);

            if (layer.LayerType == CompLayerTypes.LookCamera ||
                layer.LayerType == CompLayerTypes.FreeCamera)
            {
                cm.Items.Add(new Separator());

                // Active camera
                mi = new MenuItem();
                mi.Name = "ActiveCamera";
                mi.Header = "Active Camera";
                myBinding = new Binding("IsActiveCamera");
                myBinding.Mode = BindingMode.OneWay;
                myBinding.Source = layer;
                mi.SetBinding(MenuItem.IsCheckedProperty, myBinding);
                mi.Command = IsActiveCamera_ClickedCommand;
                cm.Items.Add(mi);
            }

            if (layer.LayerType == CompLayerTypes.ReplayData)
            {
                cm.Items.Add(new Separator());

                // Bake to null
                mi = new MenuItem();
                mi.Name = "BakeToNull";
                mi.Header = "Bake To Null";
                mi.Command = BakeToNullClickedCommand;
                cm.Items.Add(mi);
            }

            cm.Items.Add(new Separator());

            mi = new MenuItem();
            mi.Name = "RenameLayer";
            mi.Header = "Rename Layer";
            mi.Command = RenameLayer_ClickedCommand;
            cm.Items.Add(mi);

            mi = new MenuItem();
            mi.Name = "DeleteLayer";
            mi.Header = "Delete Layer";
            mi.Command = DeleteLayer_ClickedCommand;
            cm.Items.Add(mi);

            LayerNameSelectionBackground.ContextMenu = cm;
        }

        // IsActiveCamera_ClickedCommand
        RelayCommand _isActiveCamera_ClickedCommand;
        public ICommand IsActiveCamera_ClickedCommand
        {
            get
            {
                if (_isActiveCamera_ClickedCommand == null)
                    _isActiveCamera_ClickedCommand = new RelayCommand(param => this.IsActiveCamera_ClickedCommandExecute(),
                                                                      param => this.IsActiveCamera_ClickedCommandCanExecute());
                return _isActiveCamera_ClickedCommand;
            }
        }
        void IsActiveCamera_ClickedCommandExecute()
        {
            LfsRecordController.project.DeselectActiveCamera();
            ((CompLayerBase)DataContext).IsActiveCamera = true;
            ServicesFactory.EventService.GetEvent<CompLayerPropertyChangedEvent>().Publish(new CompLayerPropertyChangedEventArgs() { Sender = this, PropertyType = "IsActiveCamera", UpdateCurrentValues = true });
        }
        bool IsActiveCamera_ClickedCommandCanExecute()
        {
            if (DataContext == null)
                return false;
            return (((CompLayerBase)DataContext).LayerType == CompLayerTypes.LookCamera ||
                    ((CompLayerBase)DataContext).LayerType == CompLayerTypes.FreeCamera) ? true : false;
        }

        // Delete layer command
        RelayCommand _deleteLayer_ClickedCommand;
        public ICommand DeleteLayer_ClickedCommand
        {
            get
            {
                if (_deleteLayer_ClickedCommand == null)
                    _deleteLayer_ClickedCommand = new RelayCommand(param => this.DeleteLayer_ClickedCommandExecute());
                return _deleteLayer_ClickedCommand;
            }
        }
        void DeleteLayer_ClickedCommandExecute()
        {
            int layerIndex = ((CompLayerBase)DataContext).LayerIndex;
            LfsRecordController.RecordUserAction(new UserActionDeleteLayer()
                {
                    LayerIndex = layerIndex,
                    Layer = LfsRecordController.project.Layers[layerIndex].DataStructure()
                });
            LfsRecordController.project.DeleteLayer((CompLayerBase)DataContext);
            LfsRecordController.CreateUndoLevel();
        }

        // RenameLayer_ClickedCommand
        RelayCommand _renameLayer_ClickedCommand;
        public ICommand RenameLayer_ClickedCommand
        {
            get
            {
                if (_renameLayer_ClickedCommand == null)
                    _renameLayer_ClickedCommand = new RelayCommand(param => this.RenameLayer_ClickedCommandExecute());
                return _renameLayer_ClickedCommand;
            }
        }
        void RenameLayer_ClickedCommandExecute()
        {
            LayerRenameBox.Text = ((CompLayerBase)DataContext).LayerName;
            LayerRenameBox.Visibility = Visibility.Visible;
            LayerRenameBox.SelectAll();
            LayerRenameBox.Focus();

            LayerRenameBox.KeyDown += LayerRenameBox_KeyDown;
            Application.Current.MainWindow.PreviewMouseDown += Global_MouseDown;
        }

        private void LayerRenameBox_KeyDown(object sender, KeyEventArgs e)
        {
            //Debug.WriteLine("kb input : " + e.Key);
            if (e.Key == Key.Enter)
            {
                e.Handled = true;
                LayerRenameBox.Text = LayerRenameBox.Text.Trim();
                if (LayerRenameBox.Text.Length == 0 || LayerRenameBox.Text.Length > 23)
                    return;

                if (((CompLayerBase)DataContext).LayerName != LayerRenameBox.Text)
                {
                    LfsRecordController.RecordUserAction(new UserActionLayerNameChanged()
                        {
                            LayerType = ((CompLayerBase)DataContext).LayerType,
                            LayerIndex = ((CompLayerBase)DataContext).LayerIndex,
                            OldName = ((CompLayerBase)DataContext).LayerName,
                            NewName = LayerRenameBox.Text
                        });
                }
                ((CompLayerBase)DataContext).LayerName = LayerRenameBox.Text;

                LfsRecordController.CreateUndoLevel();
                HideInputBox();
            }
            else if (e.Key == Key.Tab)
            {
                e.Handled = true;
            }
            else if (e.Key == Key.Escape)
            {
                e.Handled = true;
                HideInputBox();
            }
        }

        private void HideInputBox(bool focusTurnAway = true)
        {
            Application.Current.MainWindow.PreviewMouseDown -= Global_MouseDown;
            LayerRenameBox.KeyDown -= LayerRenameBox_KeyDown;
            LayerRenameBox.Visibility = Visibility.Collapsed;
            if (focusTurnAway)
                Application.Current.MainWindow.Focus();
        }

        private void Global_MouseDown(object sender, MouseButtonEventArgs e)
        {
            //Debug.WriteLine("Sender type : " + e.OriginalSource.GetType());
            if (e.OriginalSource.GetType().ToString() != "System.Windows.Controls.TextBoxView")
            {
                LayerRenameBox.Text = LayerRenameBox.Text.Trim();
                if (LayerRenameBox.Text.Length > 0 && LayerRenameBox.Text.Length < 24)
                {
                    if (((CompLayerBase)DataContext).LayerName != LayerRenameBox.Text)
                    {
                        LfsRecordController.RecordUserAction(new UserActionLayerNameChanged()
                        {
                            LayerType = ((CompLayerBase)DataContext).LayerType,
                            LayerIndex = ((CompLayerBase)DataContext).LayerIndex,
                            OldName = ((CompLayerBase)DataContext).LayerName,
                            NewName = LayerRenameBox.Text
                        });
                    }
                    ((CompLayerBase)DataContext).LayerName = LayerRenameBox.Text;
                    LfsRecordController.CreateUndoLevel();
                }
                HideInputBox();
            }
        }

        // Add layer command
        RelayCommand _addLayerClickedCommand;
        public ICommand AddLayerClickedCommand
        {
            get
            {
                if (_addLayerClickedCommand == null)
                    _addLayerClickedCommand = new RelayCommand(param => AddLayer_ClickedCommandExecute(param), 
                                                               param => AddLayer_ClickedCommandCanExecute(param));
                return _addLayerClickedCommand;
            }
        }
        static void AddLayer_ClickedCommandExecute(object param)
        {
            CompLayerTypes layerType = (CompLayerTypes)param;
            CompLayerBase l = null;
            AudioLayer al = null;
            switch (layerType)
            {
                case CompLayerTypes.LookCamera:
                    l = LfsRecordController.project.AddLookCamera();
                    break;
                case CompLayerTypes.FreeCamera:
                    l = LfsRecordController.project.AddFreeCamera();
                    break;
                case CompLayerTypes.Null:
                    l = LfsRecordController.project.AddNull();
                    break;
                case CompLayerTypes.ReplayControl:
                    l = LfsRecordController.project.AddReplayControl();
                    break;
                case CompLayerTypes.ReplayData:
                    l = LfsRecordController.project.AddReplayData();
                    break;
                case CompLayerTypes.Audio:
                    al = LfsRecordController.project.AddAudio();
                    break;
            }

            if (l != null)
            {
                LfsRecordController.RecordUserAction(new UserActionAddLayer()
                {
                    LayerType = l.LayerType,
                    LayerIndex = l.LayerIndex,
                    LayerName = l.LayerName
                });
            }
            else if (al != null)
            {
                LfsRecordController.RecordUserAction(new UserActionAddLayer()
                {
                    LayerType = al.LayerType,
                    LayerIndex = al.LayerIndex,
                    LayerName = al.LayerName
                });
            }
            LfsRecordController.CreateUndoLevel();
        }
        static bool AddLayer_ClickedCommandCanExecute(object param)
        {
            if (param == null)
                return true;

            CompLayerTypes layerType = (CompLayerTypes)param;
            if (layerType == CompLayerTypes.ReplayControl)
            {
                return (LfsRecordController.project.NumLayersOfType(CompLayerTypes.ReplayControl) > 0) ? false : true;
            }
            return true;
        }

        // BakeToNullClickedCommand
        RelayCommand _bakeToNullClickedCommand;
        public ICommand BakeToNullClickedCommand
        {
            get
            {
                if (_bakeToNullClickedCommand == null)
                    _bakeToNullClickedCommand = new RelayCommand(param => this.BakeToNullClickedCommandExecute());
                return _bakeToNullClickedCommand;
            }
        }
        void BakeToNullClickedCommandExecute()
        {
            CompLayerBase l = (CompLayerBase)DataContext;
            if (l.LayerType != CompLayerTypes.ReplayData)
                return;
            CompLayerReplayData layer = (CompLayerReplayData)l;

            // show small dialog to ask for frame thinning and wether to remove the replaydata layer after conversion
            RDToNullDataTemplate tmpl = new RDToNullDataTemplate();
            RDToNullDialogBox dlg = new RDToNullDialogBox();
            dlg.DataContext = tmpl;
            dlg.Owner = App.Current.MainWindow;

            if (dlg.ShowDialog() ?? false)
            {
                Debug.WriteLine("Thinning : {0} - Delete : {1}", tmpl.FrameThinning, tmpl.CloseRDLayer);
                Mouse.OverrideCursor = Cursors.Wait;

                // Create a new null layer populated with replay data keyframes
                bool result = LfsRecordController.project.CreateNullFromReplayData(layer, tmpl.FrameThinning);

                if (result && tmpl.CloseRDLayer)
                {
                    // Delete our datacontext layer
                    LfsRecordController.RecordUserAction(new UserActionDeleteLayer()
                    {
                        LayerIndex = layer.LayerIndex,
                        Layer = layer.DataStructure()
                    });
                    LfsRecordController.project.DeleteLayer(layer);
                }
                LfsRecordController.CreateUndoLevel();
                Mouse.OverrideCursor = null;
            }
        }
    }
}
